package com.himaci.gtbattle.model;

import com.himaci.gtbattle.model.character.Archer;
import com.himaci.gtbattle.model.character.Mage;
import com.himaci.gtbattle.model.character.Priest;

/**
 * Kelas abstrak untuk karakter dalam game
 *
 * @author XNPSDN
 */
public abstract class GameChar {

    // daftar state karakter
    public static final int STATE_READY = 0;
    public static final int STATE_ATTACKING = 1;
    public static final int STATE_SKILLING = 2;
    public static final int STATE_ATTACKED = 3;
    public static final int STATE_SUPPORTED = 4;
    public static final int STATE_DEAD = 5;
    // time
    public static final float ATTACKING_ANIM_TIME = 1.0f;
    public static final float ATTACKED_ANIM_TIME = 1.0f;
    // daftar buff karakter
    public static final int BUFF_NONE = 0;
    public static final int BUFF_SILENT = 1;
    public static final int BUFF_CURSED = 2;
    // data
    public Player owner;
    public Skill[] skills;
    // atribut karakter
    public int baseAttack;
    public int baseDefense;
    public int maxVitality;
    public int maxEnergy;
    public int currAttack;
    public int currDefense;
    public int currVitality;
    public int currEnergy;
    // state manager
    public int buff;
    public int buffCounter;
    public int state;
    public float stateTime;

    /**
     * Konstruktor
     */
    public GameChar() {
	// nothing todo here
    }

    /**
     * Konstruktor
     * @param attack Base attack dari karakter
     * @param defense Base defense dari karakter
     * @param maxVitality Max vitality dari karakter
     * @param maxEnergy Max energy dari karakter
     */
    public GameChar(Player owner, int attack, int defense, int maxVitality, int maxEnergy) {
	this.owner = owner;
	skills = new Skill[3];

	baseAttack = attack;
	baseDefense = defense;
	this.maxVitality = maxVitality;
	this.maxEnergy = maxEnergy;

	currAttack = attack;
	currDefense = defense;
	currVitality = maxVitality;
	currEnergy = maxEnergy;

	buff = BUFF_NONE;
	buffCounter = 0;
	state = STATE_READY;
	stateTime = 0;
    }

    /**
     * Mengkopi value dari character
     * @return Karakter baru
     */
    public GameChar copy(Player owner) {
	GameChar retVal = null;
	if (this instanceof Archer) {
	    retVal = new Archer();
	} else if (this instanceof Mage) {
	    retVal = new Mage();
	} else if (this instanceof Priest) {
	    retVal = new Priest();
	}

	retVal.owner = owner;
	retVal.skills = skills;

	retVal.baseAttack = baseAttack;
	retVal.baseDefense = baseDefense;
	retVal.maxVitality = maxVitality;
	retVal.maxEnergy = maxEnergy;

	retVal.currAttack = currAttack;
	retVal.currDefense = currDefense;
	retVal.currEnergy = currEnergy;
	retVal.currVitality = currVitality;

	retVal.buff = buff;
	retVal.buffCounter = buffCounter;
	retVal.state = state;
	retVal.stateTime = stateTime;

	return retVal;
    }

    /**
     * Get current attack
     * @return Mengambil attack
     */
    public int getAttack() {
	if (buff == BUFF_CURSED) {
	    return currAttack / 2;
	}
	return currAttack;
    }

    /**
     * Update karakter
     * @param deltaTime Selisih waktu
     */
    public void update(float deltaTime) {
	stateTime += deltaTime;
	if ((state == STATE_ATTACKING && stateTime > ATTACKING_ANIM_TIME)
		|| (state == STATE_SKILLING && stateTime > ATTACKING_ANIM_TIME)
		|| (state == STATE_SUPPORTED && stateTime > ATTACKED_ANIM_TIME)
		|| (state == STATE_ATTACKED && stateTime > ATTACKED_ANIM_TIME)) {
	    if (currVitality <= 0) {
		state = STATE_DEAD;
	    } else {
		state = STATE_READY;
	    }
	    stateTime = 0;
	}
    }

    /**
     * Apakah dia bisa make skill?
     * @param skillNumber Nomor skill 0-2
     * @return Bisa atau tidak
     */
    public boolean canUseSkill(int skillNumber) {
	if (isDead() || isSilenced() || currEnergy < skills[skillNumber].manaCost) {
	    return false;
	}
	return true;
    }

    /**
     * Apakah sudah siap (tidak sedang animasi)
     * @return Siap atau tidak
     */
    public boolean isReady() {
	return state == STATE_READY || state == STATE_DEAD;
    }

    /**
     * Apakah sudah mati
     * @return Mati atau tidak
     */
    public boolean isDead() {
	//return currVitality <= 0;
	return state == STATE_DEAD;
    }

    /**
     * Attack secara normal ke karakter lain
     * @param target Karakter target
     */
    public void attack(GameChar target) {
	// kalkulasi damage
	int damage = getAttack() * (100 - target.currDefense) / 100;

	// mengurangi vitalitas lawan berdasarkan damage
	target.currVitality -= damage;
	if (target.currVitality < 0) {
	    target.currVitality = 0;
	}

	target.state = GameChar.STATE_ATTACKED;
	target.stateTime = 0;
    }

    /**
     * Attack secara normal ke karakter lain
     * @param target Karakter target
     */
    public void attack(GameChar target, float multiplier) {
	// kalkulasi damage
	int damage = (int) ((float) getAttack() * multiplier) * (100 - target.currDefense) / 100;

	// mengurangi vitalitas lawan berdasarkan damage
	target.currVitality -= damage;
	if (target.currVitality < 0) {
	    target.currVitality = 0;
	}

	target.state = GameChar.STATE_ATTACKED;
	target.stateTime = 0;
    }

    /**
     * Execute skill terhadap target
     * @param target Target
     * @param skill Skill yang digunakan
     */
    public void skill(GameChar target, Skill skill) {
	skill.execute(this, target);
    }

    /**
     * Apakah sedang terkena cursed atau tidak
     * @return Terkena cursed atau tidak
     */
    public boolean isCursed() {
	return buff == BUFF_CURSED && buffCounter > 0;
    }

    /**
     * Apakah terkena silent atau tidak
     * @return Terkena silent atau tidak
     */
    public boolean isSilenced() {
	return buff == BUFF_SILENT && buffCounter > 0;
    }

    /**
     * Curse character
     */
    public void curse() {
	buff = GameChar.BUFF_CURSED;
	buffCounter = 2;
	//currAttack = currAttack / 2;	

	state = STATE_ATTACKED;
	stateTime = 0;
    }

    /**
     * Silence character
     */
    public void silence() {
	buff = GameChar.BUFF_SILENT;
	buffCounter = 2;

	state = STATE_ATTACKED;
	stateTime = 0;
    }

    /**
     * Hilangkan cursed terhadap character
     */
    public void removeCursed() {
	buff = BUFF_NONE;
	buffCounter = 0;
	//currAttack = currAttack * 2;

	state = STATE_SUPPORTED;
	stateTime = 0;
    }

    /**
     * Hilangkan silent terhadap character
     */
    public void removeSilent() {
	buff = BUFF_NONE;
	buffCounter = 0;

	state = STATE_SUPPORTED;
	stateTime = 0;
    }
    
    // meh
    public void animAttack() {
	state = STATE_ATTACKING;
	stateTime = 0;
    }
    
    public void animSkill() {
	state = STATE_SKILLING;
	stateTime = 0;
    }
}
